package com.ufop.model;

import java.awt.TextArea;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Observable;
import java.util.TooManyListenersException;

import javax.comm.CommPortIdentifier;
import javax.comm.CommPortOwnershipListener;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;

public class Dispositivo extends Observable implements SerialPortEventListener{
	private CommPortIdentifier portId;
	private SerialPort sPort;
	private static String pID = "COM1";
	private OutputStream os;
    private InputStream is;
    private boolean open;
    private String messageAreaOut;
    private String messageAreaIn;
	
    public void fecharConexao() {
    	// If port is alread closed just return.
    	if (!open) {
    		return;
    	}

    	// Remove the key listener.
    	limpaMensagens();
//    	messageAreaOut.removeKeyListener(keyHandler);

    	// Check to make sure sPort has reference to avoid a NPE.
    	if (sPort != null) {
    		try {
    			// close the i/o streams.
    			os.close();
    			is.close();
    		} catch (IOException e) {
    			System.err.println(e);
    		}

    		// Close the port.
    		sPort.close();

    		// Remove the ownership listener.
//    		portId.removePortOwnershipListener(this);
    	}

    	open = false;
    	setChanged();
    	notifyObservers("desconectado");
    }

	public void abrirConexao() throws Exception{
		try{
			sPort = (SerialPort)CommPortIdentifier.getPortIdentifier(getpID()).open("SistemaVotacao", 30000);
			sPort.setSerialPortParams(9600,
					SerialPort.DATABITS_8,
					SerialPort.STOPBITS_1,
					SerialPort.PARITY_NONE);				
			sPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
		}catch (UnsupportedCommOperationException e) {
			System.out.println(e);
			
			sPort.close();
			throw e;
		}
		
		// Open the input and output streams for the connection. If they won't
		// open, close the port before throwing an exception.
		try {
		    os = sPort.getOutputStream();
		    is = sPort.getInputStream();
		} catch (IOException e) {
		    sPort.close();
		    throw new Exception("Error opening i/o streams");
		}
		// Add this object as an event listener for the serial port.
		try {
		    sPort.addEventListener(this);
		} catch (TooManyListenersException e) {
		    sPort.close();
		    throw new Exception("too many listeners added");
		}
		// Set notifyOnDataAvailable to true to allow event driven input.
		sPort.notifyOnDataAvailable(true);

		// Set notifyOnBreakInterrup to allow event driven break handling.
		sPort.notifyOnBreakInterrupt(true);

		// Set receive timeout to allow breaking out of polling loop during
		// input handling.
		try {
		    sPort.enableReceiveTimeout(30);
		} catch (UnsupportedCommOperationException e) {
		}

		// Add ownership listener to allow ownership event handling.
//		portId.addPortOwnershipListener(this);
		open = true;
				
		//notifica ouvintes
		setChanged();
		notifyObservers("conectado");
	}
	

	@Override
	public void serialEvent(SerialPortEvent e) {
		// Create a StringBuffer and int to receive input data.
		StringBuffer inputBuffer = new StringBuffer();
		int newData = 0;

		// Determine type of event.
		switch (e.getEventType()) {

		    // Read data until -1 is returned. If \r is received substitute
		    // \n for correct newline handling.
		    case SerialPortEvent.DATA_AVAILABLE:
			    while (newData != -1) {
			    	try {
			    	    newData = is.read();
				    if (newData == -1) {
					break;
				    }
				    if ('\r' == (char)newData) {
				   	inputBuffer.append('\n');
				    } else {
				    	inputBuffer.append((char)newData);
				    }
			    	} catch (IOException ex) {
			    	    System.err.println(ex);
			    	    return;
			      	}
	   		    }

			// Append received data to messageAreaIn.
			setMessageAreaIn(new String(inputBuffer));
			break;

		    // If break event append BREAK RECEIVED message.
		    case SerialPortEvent.BI:
			setMessageAreaIn("\n--- BREAK RECEIVED ---\n");
		}		
	}	
	
	public void atribuirVoto(String pacote){
		
	}
	
	public void enviaMensagemDispositivo(String pacote){
		
	}
	
	public static String getpID() {
		return pID;
	}

	public static void setpID(String pID) {
		Dispositivo.pID = pID;
	}

	public CommPortIdentifier getPortId() {
		return portId;
	}

	public void setPortId(CommPortIdentifier portId) {
		this.portId = portId;
	}

	public SerialPort getsPort() {
		return sPort;
	}

	public void setsPort(SerialPort sPort) {
		this.sPort = sPort;
	}

	public String getMessageAreaOut() {
		return messageAreaOut;
	}

	public void limpaMensagens(){
		messageAreaIn = "";
		messageAreaOut = "";
		setChanged();
		notifyObservers("limpar");
	}
	
	public void setMessageAreaOut(String messageAreaOut){
		try{
			for(int i = 0; i < messageAreaOut.length(); i++)
				os.write((int)messageAreaOut.charAt(i));
			this.messageAreaOut += messageAreaOut + "\n";
			setChanged();
			notifyObservers("enviaMensagem");
		}catch(Exception e){
			System.out.println(e);
		}
	}

	public String getMessageAreaIn() {
		return messageAreaIn;
	}

	public void setMessageAreaIn(String messageAreaIn) {
		this.messageAreaIn += messageAreaIn;
		setChanged();
		notifyObservers("novaMensagem");
	}
}
